package com.uinnova.product.eam.service.impl;

import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.model.permissionV2.*;
import com.uinnova.product.eam.service.UserRoleRltV2Svc;
import com.uino.bean.permission.base.SysOrgRoleRlt;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.base.SysUserOrgRlt;
import com.uino.bean.permission.base.SysUserRoleRlt;
import com.uino.bean.permission.query.CSysUser;
import com.uino.dao.permission.ESUserSvc;
import com.uino.dao.permission.rlt.ESOrgRoleRltSvc;
import com.uino.dao.permission.rlt.ESPerssionCommSvc;
import com.uino.dao.permission.rlt.ESUserRoleRltSvc;
import com.uino.dao.util.ESUtil;
import com.uino.util.sys.SysUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class UserRoleRltV2SvcImpl implements UserRoleRltV2Svc {

    @Autowired
    private ESUserSvc userSvc;
    @Autowired
    private ESPerssionCommSvc commSvc;
    @Autowired
    private ESOrgRoleRltSvc orgRoleRltSvc;
    @Autowired
    private ESUserRoleRltSvc userRoleRltSvc;

    @Override
    public Page<UserQueryRes> userPage(UserQueryReq req) {
        Assert.notNull(req.getRoleId(), "角色id不能为空");
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        String keyword = req.getKeyword();
        Assert.isTrue(BinaryUtils.isEmpty(keyword) || keyword.trim().length() <= 200, "BS_SEARCH_LENGTH_ERR");
        query.must(QueryBuilders.rangeQuery("id").from(1));
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        if (StringUtils.isNotBlank(keyword)) {
            query.must(QueryBuilders.multiMatchQuery(keyword, "userName", "loginCode").operator(Operator.AND)
                    .type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).lenient(true));
        }
        List<SortBuilder<?>> sorts = new LinkedList<>();
        sorts.add(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
        sorts.add(SortBuilders.fieldSort("id").order(SortOrder.ASC));
        Page<SysUser> page = userSvc.getSortListByQuery(req.getPageNum(), req.getPageSize(), query, sorts);
        List<SysUser> sysUsers = page.getData();
        if (CollectionUtils.isEmpty(sysUsers)) {
            return trans(page, new HashSet<>(), new HashSet<>());
        }
        //填充用户角色
        //获取用户-角色
        Set<Long> userIds = sysUsers.stream().map(SysUser::getId).collect(Collectors.toSet());
        BoolQueryBuilder usrRoleRltQuery = QueryBuilders.boolQuery();
        usrRoleRltQuery.must(QueryBuilders.termQuery("roleId", req.getRoleId()));
        usrRoleRltQuery.must(QueryBuilders.termsQuery("userId", userIds));
        List<SysUserRoleRlt> sysUserRoleRlts = userRoleRltSvc.getListByQuery(1, 9999, usrRoleRltQuery).getData();
        Set<Long> roleUserIds = new HashSet<>();
        if (!CollectionUtils.isEmpty(sysUserRoleRlts)) {
            roleUserIds = sysUserRoleRlts.stream().map(SysUserRoleRlt::getUserId).collect(Collectors.toSet());
        }

        //用户所属组织
        Set<Long> orgRoleUserIds = new HashSet<>();
        List<SysUserOrgRlt> uOrgRlts = commSvc.getUserOrgRltByUserIds(userIds);
        if (!CollectionUtils.isEmpty(uOrgRlts)) {
            //获取拥有当前角色的组织
            List<SysOrgRoleRlt> orgRoleRlts = orgRoleRltSvc.getListByQuery(1, 9999,
                    QueryBuilders.boolQuery().must(QueryBuilders.termQuery("roleId", req.getRoleId()))).getData();
            if (!CollectionUtils.isEmpty(orgRoleRlts)) {
                Set<Long> roleOrgIds = orgRoleRlts.stream().map(SysOrgRoleRlt::getOrgId).collect(Collectors.toSet());
                Map<Long, List<SysUserOrgRlt>> usrOrgGroupByOrgId = uOrgRlts.stream().collect(Collectors.groupingBy(SysUserOrgRlt::getOrgId));
                for (Map.Entry<Long, List<SysUserOrgRlt>> entry : usrOrgGroupByOrgId.entrySet()) {
                    if (!roleOrgIds.contains(entry.getKey())) {
                        continue;
                    }
                    List<SysUserOrgRlt> sysUserOrgRlts = entry.getValue();
                    orgRoleUserIds.addAll(sysUserOrgRlts.stream().map(SysUserOrgRlt::getUserId).collect(Collectors.toSet()));
                }
            }
        }

        return trans(page, orgRoleUserIds, roleUserIds);
    }

    private Page<UserQueryRes> trans(Page<SysUser> page, Set<Long> orgRoleUserIds, Set<Long> roleUserIds) {
        List<UserQueryRes> resV2s = new ArrayList<>();
        if (!CollectionUtils.isEmpty(page.getData())) {
            for (SysUser user : page.getData()) {
                UserQueryRes resV2 = EamUtil.copy(user, UserQueryRes.class);
                resV2.setOrgRole(orgRoleUserIds.contains(user.getId()));
                resV2.setUserRole(roleUserIds.contains(user.getId()));
                resV2s.add(resV2);
            }
        }
        Page<UserQueryRes> result = new Page<>();
        result.setTotalPages(page.getTotalPages());
        result.setTotalRows(page.getTotalRows());
        result.setPageNum(page.getPageNum());
        result.setPageSize(page.getPageSize());
        result.setData(resV2s);
        return result;
    }

    @Override
    public Page<UserRoleRltRes> userRoleRlt(UserRoleRltReq req) {
        Assert.notNull(req.getRoleId(), "角色id不能为空");
        List<SortBuilder<?>> sorts = new LinkedList<>();
        sorts.add(SortBuilders.fieldSort("modifyTime").order(SortOrder.DESC));
        sorts.add(SortBuilders.fieldSort("id").order(SortOrder.ASC));
        BoolQueryBuilder roleQuery = QueryBuilders.boolQuery();
        if (StringUtils.isNotBlank(req.getKeyword())) {
            BoolQueryBuilder userQuery = QueryBuilders.boolQuery();
            userQuery.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
            userQuery.must(QueryBuilders.multiMatchQuery(req.getKeyword(), "userName", "loginCode").operator(Operator.AND)
                    .type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).lenient(true));
            List<SortBuilder<?>> userSorts = new LinkedList<>();
            userSorts.add(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
            userSorts.add(SortBuilders.fieldSort("id").order(SortOrder.ASC));
            Page<SysUser> page = userSvc.getSortListByQuery(req.getPageNum(), req.getPageSize(), userQuery, userSorts);
            if (CollectionUtils.isEmpty(page.getData())) {
                return new Page<>(req.getPageNum(), req.getPageSize(), 0, 0, new ArrayList<>());
            }
            Set<Long> userIds = page.getData().stream().map(SysUser::getId).collect(Collectors.toSet());
            roleQuery.must(QueryBuilders.termsQuery("userId", userIds));
        }
        roleQuery.must(QueryBuilders.termQuery("roleId", req.getRoleId()));
        Page<SysUserRoleRlt> page = userRoleRltSvc.getSortListByQuery(req.getPageNum(), req.getPageSize(), roleQuery, sorts);
        List<SysUserRoleRlt> userRoleRlts = page.getData();
        if (CollectionUtils.isEmpty(userRoleRlts)) {
            return trans(page, new ConcurrentHashMap<>());
        }
        Set<Long> userIds = userRoleRlts.stream().map(SysUserRoleRlt::getUserId).collect(Collectors.toSet());
        CSysUser ctd = new CSysUser();
        ctd.setIds(userIds.toArray(new Long[userIds.size()]));
        ctd.setDomainId(1L);
        List<SysUser> sysUsers = userSvc.getListByCdt(ctd);
        Map<Long, SysUser> userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, e -> e, (k1,k2) -> k1));
        return trans(page, userMap);
    }

    private Page<UserRoleRltRes> trans(Page<SysUserRoleRlt> page, Map<Long, SysUser> userMap) {
        List<UserRoleRltRes> resV2s = new ArrayList<>();
        if (!CollectionUtils.isEmpty(page.getData())) {
            for (SysUserRoleRlt userRoleRlt : page.getData()) {
                UserRoleRltRes res = new UserRoleRltRes();
                res.setId(userRoleRlt.getId());
                res.setUserId(userRoleRlt.getUserId());
                res.setRoleId(userRoleRlt.getRoleId());
                SysUser user = userMap.getOrDefault(userRoleRlt.getUserId(), new SysUser());
                res.setUserName(user.getUserName());
                res.setLoginCode(user.getLoginCode());
                resV2s.add(res);
            }
        }
        Page<UserRoleRltRes> result = new Page<>();
        result.setTotalPages(page.getTotalPages());
        result.setTotalRows(page.getTotalRows());
        result.setPageNum(page.getPageNum());
        result.setPageSize(page.getPageSize());
        result.setData(resV2s);
        return result;
    }

    @Override
    public void userRoleRltOp(UserRoleOpReq req) {
        Assert.notNull(req.getUserId(), "用户id不能为空");
        Assert.notNull(req.getRoleId(), "用户id不能为空");
        Assert.notNull(req.getOpType(), "操作类型不能为空");
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("userId", req.getUserId()));
        query.must(QueryBuilders.termQuery("roleId", req.getRoleId()));
        List<SysUserRoleRlt> userRoleRlts = userRoleRltSvc.getListByQuery(query);
        switch (req.getOpType()) {
            case ADD:
                if (!CollectionUtils.isEmpty(userRoleRlts)) {
                    return;
                }
                SysUserRoleRlt userRoleRlt = new SysUserRoleRlt();
                userRoleRlt.setId(ESUtil.getUUID());
                userRoleRlt.setUserId(req.getUserId());
                userRoleRlt.setRoleId(req.getRoleId());
                userRoleRltSvc.saveOrUpdate(userRoleRlt);
                break;
            case DROP:
                if (CollectionUtils.isEmpty(userRoleRlts)) {
                    return;
                }
                userRoleRltSvc.deleteByIds(userRoleRlts.stream().map(SysUserRoleRlt::getId).collect(Collectors.toSet()));
                break;
            default:
                throw new BinaryException("不支持的操作类型");
        }
    }
}
